package sketch.generator;

import java.util.LinkedList;
import java.util.List;

import sketch.BatchExecution;
import sketch.ExecutableSequenceContent;
import sketch.SketchSequence;
import sketch.skeleton.Skeleton;
import sketch.util.Checker;

public class UnitTestGenerator<T extends SketchSequence> extends CompositeGenerator<SketchSequence> {
	
	//the number of sequence generators inside the unit test generator
	public final List<SequenceGenerator<T>> seqgenerators = new LinkedList<SequenceGenerator<T>>();
	
	//public final Skeleton skeleton;
	
	public UnitTestGenerator(/*Skeleton skeleton*/) {
		super();
//		Checker.checkNull(skeleton, "The skeleton input could not be null.");
//		this.skeleton = skeleton;
	}
	
	public UnitTestGenerator(/*Skeleton skeleton,*/ SequenceGenerator<T>... seqGenerators) {
		this();
		Checker.checkNull(seqGenerators, "The seq generators array input could not be null!");
		for(SequenceGenerator<T> seqGenerator : seqGenerators) {
			this.addSequenceGenerator(seqGenerator);
		}
		//reset();
	}
	
	public UnitTestGenerator(/*Skeleton skeleton,*/ List<SequenceGenerator<T>> seqGenerators) {
		this();
		Checker.checkNull(seqGenerators, "The seq generator list input could not be null!");
		for(SequenceGenerator<T> seqGenerator : seqGenerators) {
			this.addSequenceGenerator(seqGenerator);
		}
		//reset();
	}
	
	/**
	 * For external client to add new generators, after adding, it will call reset() to restore
	 * the state.
	 * */
	public void addSequenceGenerators(SequenceGenerator<T>... seqGenerators) {
		Checker.checkNull(seqGenerators, "The sequence generators could not be null!");
		for(SequenceGenerator<T> seqGenerator : seqGenerators) {
			this.addSequenceGenerator(seqGenerator);
		}
		this.reset();
	}
	
	public void addSequenceGenerator(SequenceGenerator<T> seqGenerator) {
		Checker.checkNull(seqGenerator, "The sequence generator could not be null!");
		seqgenerators.add(seqGenerator);
	}
	
	@Override
	public void reset() {
		super.reset();
		for(SequenceGenerator<?> seqgenerator : seqgenerators) {
			seqgenerator.reset();
		}
	}
	
	public List<ExecutableSequenceContent[]> getExecutableContentList() {
		List<ExecutableSequenceContent[]> list = new LinkedList<ExecutableSequenceContent[]>();
		for(SequenceGenerator<T> generator : this.seqgenerators) {
			list.add(generator.getExecutionContents());
		}
		return list;
	}
	
	public List<BatchExecution> getExecutionResults() {
		List<BatchExecution> list = new LinkedList<BatchExecution>();
		
		for(SequenceGenerator<T> generator : this.seqgenerators) {
			list.add(generator.getExecutionResults());
		}
		
		return list;
	}

	@Override
	public SketchSequence generateCurrent() {
		//the sequence to produce
		SketchSequence retSequence = new SketchSequence();
		
		//assembly the sequence from all generators
//		int numberOfGenerator = 0;
		for(SequenceGenerator<T> generator : this.seqgenerators) {
			SketchSequence genSeq = (SketchSequence)generator.current();
			//mocking for output
			retSequence = retSequence.appendText(genSeq);
			
			//see the execution result
//			BatchExecution batchExec = generator.getExecutionResults();
//			System.out.println(batchExec);
		}
		
		return retSequence;
	}

	@Override
	public IIterationLink getInitializedIterator() {
		List<IGenerator<?>> generatorList = new LinkedList<IGenerator<?>>();
		
		for(IGenerator<?> generator : this.seqgenerators) {
			generatorList.add(generator);
		}

		//the generation order is important here!
		return LinkCreator.createInOrderGenCombinatoricLink(generatorList);
	}
}